#include "Widget.hpp"
namespace mi
{
  Widget::Widget(WidgetType type, std::string newText, std::string ID)
  {
    if (defaultFontNotInit)
    {
      defaultFontSize = 18;
      if(!defaultFont.loadFromFile("./resources/fonts/default/default.ttf"))
      {
        LOG_ERROR << "failed to load /resources/fonts/default/default.ttf";
        defaultFont = sf::Font();
      }
      sizableText.setFont(defaultFont);
      sizableText.setCharacterSize(defaultFontSize);
      defaultFontNotInit = false;
      sizableText.setString("W!Agpqf");
      lineHeight = sizableText.getGlobalBounds().height;
      titlebarTexture = new sf::Texture();
      titlebarTexture->loadFromFile("./resources/textures/ui/widget/titlebar.png");
      TMP_TEST_TEX = new sf::Texture();
      TMP_TEST_TEX->loadFromFile("./resources/textures/ui/widget/test.png");
    }

    this->type = type;
    text = newText;

    if (ID.length() > 0)
      this->ID = "ID_" + ID;
    else
      this->ID = GenerateUniqueID();

    widgetCount ++;
  }

  Widget::~Widget()
  {
    widgetCount--;
  }

  void Widget::SetID(std::string newID)
  {
    if (newID.length() > 0)
      ID = "ID_" + newID;
    else
      ID = GenerateUniqueID();
  }

  void Widget::SetText(std::string newText)
  {
    text = newText;
    OnTextChanged();
  }

  std::string Widget::GetID()
  {
    return ID.substr(3);
  }

  std::string Widget::GetInternalID()
  {
    return ID;
  }

  std::string Widget::GetText()
  {
    return text;
  }

  WidgetType Widget::GetType()
  {
    return type;
  }

  // TODO: These should not be public to be honest, but for now this solution may work
  void Widget::SetSize (Vec2i size)
  {
    if (size.x < 10)
      size.x = 10;
    if (size.y < 0)
      size.y = 0;

    Vec2i oldSize = this->size;
    this->size = size;
    OnSizeChange(oldSize);
  }

  void Widget::SetPos (Vec2i pos)
  {
    if (pos.x + size.x > (int)App::I().GetWindow().getSize().x)
      pos.x = (int)App::I().GetWindow().getSize().x - size.x;

    if (pos.x < 0)
      pos.x = 0;

    if (pos.y < 0)
      pos.y = 0;

    if (pos.y + size.y > (int)App::I().GetWindow().getSize().y)
      pos.y = (int)App::I().GetWindow().getSize().y - size.y;
    
    Vec2i oldPosition = position;
    position = pos;
    OnPositionChange(oldPosition);
  }

  Vec2i Widget::GetSize ()
  {
    return size;
  }

  Vec2i Widget::GetPos ()
  {
    return position;
  }

  bool Widget::Contains(Widget* other)
  {
    return (other == this);
  }

  Widget* Widget::MouseClick(sf::Mouse::Button button, sf::MouseState state, int x, int y)
  {
    return NULL;
  }
  
  Widget* Widget::MouseMoved(int x, int y, int dx, int dy)
  {
    return NULL;
  }
  
  Widget* Widget::MouseDragged(int x, int y, int dx, int dy)
  {
    return NULL;
  }
  
  Widget* Widget::MouseWheel(int dir)
  {
    return NULL;
  }
  
  Widget* Widget::KeysDown(sf::Event::KeyEvent key)
  {
    return NULL;
  }
  
  Widget* Widget::KeysUp(sf::Event::KeyEvent key)
  {
    return NULL;
  }

  Widget* Widget::TextEntered(char ch)
  {
    return NULL;
  }

  // private

  void Widget::SetTextPos(sf::Text &txt, Vec2i pos)
  {
    sf::FloatRect s = txt.getLocalBounds();
    txt.setPosition((float)pos.x, (float)(apph - pos.y - lineHeight));
  }

  void Widget::RenderText (sf::Text txt)
  {
    App::I().GetWindow().draw(txt);
  }

  Vec2i Widget::GetTextSize (std::string txt)
  {
    sizableText.setString(txt);
    return Vec2i(sizableText.getGlobalBounds().width, sizableText.getLocalBounds().height);
  }

  void Widget::DrawBackground (Vec2i start, Vec2i end)
  { 
    DrawQuad(start, end);
    //DrawNinePatch(start, end, 30, 60, 10, 40, 40, 40, 40, 40, TMP_TEST_TEX);
  }

  void Widget::DrawFace (Vec2i start, Vec2i end)
  {
    DrawQuad(start, end);
  }

  void Widget::DrawTitle (Vec2i start, Vec2i end)
  {
    DrawNinePatch(start, end, 10, 0, 10, 10, 20, 0, 20, 20, titlebarTexture);
  }

  bool Widget::IsMouseInBody(Vec2i mouse)
  {
    return (mouse.x >= position.x &&
            mouse.x <= position.x + size.x &&
            mouse.y <= position.y + size.y &&
            mouse.y >= position.y);
  }

  void Widget::OnTextChanged()
  {
    // do nothing
  }

  void Widget::OnSizeChange(Vec2i oldSize)
  {
    // do nothing
  }

  void Widget::OnPositionChange(Vec2i oldPosition)
  {
    // do nothing
  }

  unsigned long Widget::uniqueid = 0;

  std::string Widget::GenerateUniqueID()
  {
    std::string ID = "UD_" + fToS(uniqueid);
    uniqueid++;
    return ID;
  }

  void Widget::DrawQuad(Vec2i start, Vec2i end, sf::Texture *texture, Vec3d topColor, unsigned int opacity)
  {
    quad.setPosition((float)start.x, apph - (float)end.y);
    quad.setSize(sf::Vector2f(end.x - start.x, end.y - start.y));
    
    quad.setFillColor(sf::Color((sf::Uint8)(topColor.x*255.0),
                                (sf::Uint8)(topColor.y*255.0),
                                (sf::Uint8)(topColor.z*255.0),
                                opacity) );

    quad.setTexture(texture);
    if (texture != NULL)
      quad.setTextureRect(sf::IntRect(0,0,texture->getSize().x, texture->getSize().y));
    // NOTE TO SELF: May be beneficial to have 2 quads - one for DrawQuad, one for DrawNinePatch

    App::I().GetWindow().draw(quad);
    
    return;
  }

  void Widget::DrawNinePatch(Vec2i start, Vec2i end,
                       int left, int top, int right, int bottom,
                       int imgLeft, int imgTop, int imgRight, int imgBottom,
                       sf::Texture *texture)
    {
      int tmp;
      if (start.x > end.x)
      {
        tmp = end.x;
        end.x = start.x;
        start.x = tmp;
      }
      if ((apph - start.y) < (apph - end.y))
      {
        tmp = end.y;
        end.y = start.y;
        start.y = tmp;
      }

      quad.setTexture(texture);
      quad.setFillColor(sf::Color::White);
      sf::RenderWindow *win = &(App::I().GetWindow());
      float texw = texture->getSize().x;
      float texh = texture->getSize().y;
      int recw = abs(start.x - end.x);
      int rech = abs(start.y - end.y);

      // TOP LEFT
      quad.setTextureRect(sf::IntRect(0, 0, imgLeft, imgTop));
      quad.setPosition(start.x, apph - end.y);
      quad.setSize(sf::Vector2f(left, top));
      win->draw(quad);

      // TOP
      quad.setTextureRect(sf::IntRect(imgLeft, 0, texw - imgLeft - imgRight , imgTop));
      quad.setPosition(start.x + left, apph - end.y);
      quad.setSize(sf::Vector2f(recw - left - right, top));
      win->draw(quad);

      // TOP RIGHT
      quad.setTextureRect(sf::IntRect(texw - imgRight, 0, imgRight , imgTop));
      quad.setPosition(end.x - right, apph - end.y);
      quad.setSize(sf::Vector2f(right, top));
      win->draw(quad);

      // LEFT
      quad.setTextureRect(sf::IntRect(0, imgTop, imgLeft, texh - imgTop - imgBottom));
      quad.setPosition(start.x, apph - (end.y - top));
      quad.setSize(sf::Vector2f(left, rech - top - bottom));
      win->draw(quad);

      // CENTER
      quad.setTextureRect(sf::IntRect(imgLeft, imgTop, texw - imgLeft - imgRight , texh - imgTop - imgBottom));
      quad.setPosition(start.x + left, apph - (end.y - top));
      quad.setSize(sf::Vector2f(recw - left - right, rech - top - bottom));
      win->draw(quad);
      
      // RIGHT
      quad.setTextureRect(sf::IntRect(texw - imgRight, imgTop, imgRight , texh - imgTop - imgBottom));
      quad.setPosition(end.x - right, apph - (end.y - top));
      quad.setSize(sf::Vector2f(right, rech - top - bottom));
      win->draw(quad);

      // BOTTOM LEFT
      quad.setTextureRect(sf::IntRect(0, texh - imgBottom, imgLeft, imgBottom));
      quad.setPosition(start.x, apph - (start.y + bottom));
      quad.setSize(sf::Vector2f(left, bottom));
      win->draw(quad);

      // BOTTOM
      quad.setTextureRect(sf::IntRect(imgLeft, texh - imgBottom, texw - imgLeft - imgRight , imgBottom));
      quad.setPosition(start.x + left, apph - (start.y + bottom));
      quad.setSize(sf::Vector2f(recw - left - right, bottom));
      win->draw(quad);

      // BOTTOM RIGHT
      quad.setTextureRect(sf::IntRect(texw - imgRight, texh - imgBottom, imgRight , imgBottom));
      quad.setPosition(end.x - right, apph - (start.y + bottom));
      quad.setSize(sf::Vector2f(right, bottom));
      win->draw(quad);

    }


  /*static*/ int Widget::widgetCount = 0;

  /*static*/ sf::RectangleShape Widget::quad;

  /*static*/ sf::Text Widget::sizableText;
  
  /*static*/ int Widget::lineHeight = 0;

  /*static*/ int Widget::apph = 0;

  /*static*/ int Widget::appw = 0;

  /*static*/ bool Widget::defaultFontNotInit = true;

  /*static*/ sf::Font Widget::defaultFont;

  /*static*/ int Widget::defaultFontSize = 20;

  /*static*/ sf::Texture * Widget::titlebarTexture = NULL;

  /*static*/ sf::Texture * Widget::TMP_TEST_TEX = NULL;

  /*static*/ void Widget::OnResize(int w, int h)
  {
    appw = w;
    apph = h;
  }
}
